package com.snow.student;

import com.snow.proto.*;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.stub.StreamObserver;

import java.time.LocalDateTime;
import java.util.Iterator;

public class StudentClient {

    public static void main(String[] args){
        for(int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    StudentClient.test();
                }
            }).start();
        }
    }
    public static void test(){
        ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 8899).usePlaintext(true).build();

        //同步、阻塞式：
        StudentServiceGrpc.StudentServiceBlockingStub blockingStub = StudentServiceGrpc.newBlockingStub(managedChannel);

        //异步：只要请求为流，那么就只能使用异步；请求不为流也可以使用异步。
        StudentServiceGrpc.StudentServiceStub stub = StudentServiceGrpc.newStub(managedChannel);

        System.out.println("------------------请求非流，响应非流：-------------------------");

        MyResponse myResponse = blockingStub.getRealNameByUsername(
                MyRequest.newBuilder().setUsername("zhangsan").build()
        );
        System.out.println(myResponse.getRealname());

        System.out.println("------------------请求非流，响应为流：-------------------------");

        Iterator<StudentResponse> iter = blockingStub.getStudentsByAge(
                StudentRequest.newBuilder().setAge(20).build()
        );
        while (iter.hasNext()){
            StudentResponse studentResponse = iter.next();
            System.out.println(studentResponse.getName() + ","
                    + studentResponse.getAge() + ","
                    + studentResponse.getCity()
            );
//            break;//客户端也可以选择不完全接收数据，但要等到服务端把数据全部传过来，否则服务端会报客户端强制关闭连接错误。
        }

        System.out.println("------------------请求为流，响应非流，响应为集合：-------------------------");

        //对服务端响应的发送来的集合进行处理
        StreamObserver<StudentResponseList> studentResponseListStreamObserver = new StreamObserver<StudentResponseList>() {
            @Override
            public void onNext(StudentResponseList value) {
                value.getStudentResponseList().forEach(studentResponse -> {
                    System.out.println(studentResponse.getName());
                    System.out.println(studentResponse.getAge());
                    System.out.println(studentResponse.getCity());
                    System.out.println("*************");
                });
            }

            @Override
            public void onError(Throwable t) {
                System.out.println(t.getMessage());
            }

            @Override
            public void onCompleted() {
                System.out.println("completed!");
            }
        };
        StreamObserver<StudentRequest> studentRequestStreamObserver = stub.getStudentsWrapperByAges(studentResponseListStreamObserver);
        //流式的请求构建：
        studentRequestStreamObserver.onNext(StudentRequest.newBuilder().setAge(20).build());
        studentRequestStreamObserver.onNext(StudentRequest.newBuilder().setAge(30).build());
//        try {
//            Thread.sleep(1000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        studentRequestStreamObserver.onNext(StudentRequest.newBuilder().setAge(40).build());
        studentRequestStreamObserver.onNext(StudentRequest.newBuilder().setAge(50).build());

        studentRequestStreamObserver.onCompleted();

        System.out.println("------------------请求为流，响应为流：-------------------------");

        StreamObserver<StreamRequest> requestStreamObserver = stub.biTalk(new StreamObserver<StreamResponse>() {
            //对服务端响应的发送来的每一块流进行处理
            @Override
            public void onNext(StreamResponse value) {
                System.out.println(value.getResponseInfo());
            }

            @Override
            public void onError(Throwable t) {
                System.out.println(t.getMessage());
            }

            @Override
            public void onCompleted() {
                System.out.println("onCompleted");
            }
        });
        //流式的请求构建：
        for (int i = 0; i < 10; i++){
            requestStreamObserver.onNext(
                    StreamRequest.newBuilder().setRequestInfo(
                            LocalDateTime.now().toString()
                        ).build()
                );
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        requestStreamObserver.onCompleted();//如果请求是流则一定要调用onCompleted，否则服务端会报客户端强制关闭连接错误。

        System.out.println("-------------------最底部------------------------");
        try {
            Thread.sleep(3000);//此句是因为使用了异步，要等待一段时间才能出结果。
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        managedChannel.shutdown();//防止强制关闭客户端造成服务端报错。
    }
    /**
     * 总结：
     *
     * 当服务端为流，客户端为流时：
     *
     * 客户端首先调用requestStreamObserver.onNext().build()，
     * 之后发送到服务端，服务端被客户端触发new StreamObserver<StreamRequest>()中的onNext()方法，
     * 服务端在new StreamObserver<StreamRequest>()中的onNext()方法调用responseObserver.onNext()方法，
     * 之后发送到客户端，客户端被服务端触发new StreamObserver<StreamResponse>()中的onNext()方法，
     * 客户端打印服务端发来的消息，
     *
     * 不断重复以上过程······
     *
     * 最后，客户端调用requestStreamObserver.onCompleted()方法，
     * 之后发送到服务端，服务端被客户端触发new StreamObserver<StreamRequest>()中的onCompleted()方法，
     * 服务端在new StreamObserver<StreamRequest>()中的onCompleted()方法中调用responseObserver.onCompleted()方法，
     * 之后发送到客户端，客户端被服务端触发new StreamObserver<StreamResponse>()中的onCompleted()方法，
     * 客户端打印字符串。
     */
}
